<?php

# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
#
#	FILE:			includes/tableproperties.php
#	FUNCTION:		Class for handling the properties (columns) of the tables
#	AUTHOR:			Cameron Morrow
#	CREATED:		28/07/2005
#
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -


/**
 * The TableProperties class handles a number of TableProperty objects. It also handles large-scale formatting
 * such as creating the browse tables, add tables, edit tables etc
*/
class TableProperties {

	# List of properties
	var $properties = array();

	# List of custom columns
	var $custom_columns = array();

	/**
	 * TableProperties() instantiates the TableProperties class
	 *
	 * @param initial_properties is an array of initial properties to add
	*/
	function TableProperties($initial_properties = array()) {

		# Key to array is property ID
		foreach ($initial_properties as $property_id => $property) {
			$this -> addProperty($property);
		}
	}

	/**
	 * addProperty() adds a property to the properties array
	 *
	 * @param new_property is the property to add
	*/
	function addProperty($new_property) {

		# If property supplied
		if ($new_property) {

			# Add
			$this -> properties[$new_property -> getID()] = $new_property;
		}
	}

	/**
	 * getProperty() gets the property with the passed ID
	 *
	 * @param property_id is the ID of the property to get
	 *
	 * @return the property
	*/
	function getProperty($property_id) {

		if (array_key_exists($property_id, $this -> properties)) {

			return $this -> properties[$property_id];

		} else {

			return false;
		}
	}


	/**
	 * getProperties returns the properties array
	 *
	 * @return the properties array
	*/
	function getProperties() {
		return $this -> properties;
	}


	/**
	 * addCustomColumn() adds a custom column
	*/
	function addCustomColumn($column_name, $column_value) {

		$this -> custom_columns[] = array("name" => $column_name, "value" => $column_value);
	}


	/**
	 * formatCustomColumn() formats a custom column
	 *
	 * @param column_content is the content to evaluate
	 * @param row_data is the data from the current row that can be used in the evaluation
	 *		To reference a row content element from column_content, use [ROW_ELEMENT_ID] (square brackets around the ID of the row element)
	*/
	function formatCustomColumn($column_content, $row_data) {

		# Insert the row content
		foreach ($row_data as $element_id => $element_content) {

			$column_content = preg_replace("/\[" . $element_id . "\]/", $element_content, $column_content);
		}

		eval("$" . "column_content = " . $column_content . ";");

		return $column_content;
	}

	/**
	 * printProperties() returns a print out of the properties
	*/
	function printProperties() {

		# Output
		$output = "<h2>printProperties()</h2>";

		foreach ($this -> properties as $key => $property) {
			$output .= $property -> printProperty();
		}

		# Return
		return $output;
	}

	/**
	 * drawBrowseTable() draws the browse table
	 *
	 * @param content_array is the content
	*/
	function drawBrowseTable($content_array = array(), $table_header = "Browsing", $group_field = "", $table_type = "users") {
		# Bring in some commonly used globals
		global $YES_NO_ARRAY;
		global $ADMIN_BROWSING_PAGE_RESULTS;
		global $PAGE_LINK_TOLERANCE;

		# Get page number of results
		$page_number = (@$_POST["result"]) ? $_POST["result"] : 1;

		# Get offset to start results at
		$result_offset = ($page_number - 1) * $ADMIN_BROWSING_PAGE_RESULTS;

		# Output to return
		$table_output = "";

		# Current value of grouping variable
		$group_value = null;

		# Count columns
		$column_count = 0;

		# Open table
		$table_output .= "<h2 class=\"" . $table_type . "\">" . $table_header . "</h2>";
		$table_output .= "<div id=\"txtHint\">";
		$table_output .= "<table class=\"admintable\" cellspacing=\"0\" id=\"admin_table\">";
		$table_output .= "<thead>";
		$table_output .= "<tr>";

		# Add main columns
		foreach ($this -> properties as $property_id => $property) {

			# If it's browse property is on...
			if ($property -> getData("tp_browsesortorder") != "0") {
				$table_output .= "<th>" . $property -> getData("tp_name") . "</th>";

				# Increment column count
				$column_count++;
			}
		}

		# Add custom columns
		foreach ($this -> custom_columns as $column_id => $column_data) {
			$table_output .= "<th>" . $column_data["name"] . "</th>";

			# Increment column count
			$column_count++;
		}

		# Close header
		$table_output .= "</tr>";
		$table_output .= "</thead>";
		$table_output .= "<tbody>";

		# Count rows to alternate colours
		$counter = 0;

		# For each row of content
		foreach ($content_array as $row_id => $row) {

			if ($counter >= $result_offset && $counter < $result_offset + $ADMIN_BROWSING_PAGE_RESULTS) {

				# Check group field
				if ($group_field != "") {
					if ($group_value != $row[$group_field]) {

						# Update value
						$group_value = $row[$group_field];
						
						# Draw
						$table_output .= "<tr class=\"rowsubheader\"><td colspan=\"" . $column_count . "\"><strong>" . $group_value . "</strong></td></tr>";
					}
				}

				# Display alternating row colours
				$table_output .= ($counter % 2 != 0) ? "<tr>" : "<tr class=\"alternate\">";

				# Add main columns
				foreach ($this -> properties as $property_id => $property) {

					if ($property -> getData("tp_browsesortorder") != "0") {

						$column_content = $this -> formatBrowse($row, $property -> getData("tp_browseformat"));

						$column_content = ($column_content == "") ? "&nbsp;" : $column_content;

						$table_output .= "<td>" . $column_content . "</td>";
					}
				}

				# Add custom columns
				foreach ($this -> custom_columns as $column_id => $column_data) {
					$table_output .= "<td>" . $this -> formatCustomColumn($column_data["value"], $row) . "</td>";
				}

				# Close row
				$table_output .= "</tr>";

			}

			# Increment counter for alternating row colours
			$counter++;
		}

		$table_output .= "</tbody>";
		$table_output .= "</table>";

		# Total number of pages
		$maximum_page = ceil(count($content_array) / $ADMIN_BROWSING_PAGE_RESULTS);

		# Paging
		$table_output .= "<div class=\"paging\">";
		
		# If paging required
		if ($maximum_page > 1) {

			$table_output .= "<p>Pages: ";

			# First
			if ($page_number > $PAGE_LINK_TOLERANCE) {
				$table_output .= "<span class=\"link\"><a href=\"javascript:pageTo(1);\"><strong>1</strong></a></span> ";
			}

			# previous
			if ($page_number > 1) {
				$table_output .= "<span class=\"link\"><a href=\"javascript:pageTo(" . ($page_number - 1) . ");\">prev</a></span> ";
			}
			
			# Indicate missing links
			if ($page_number > $PAGE_LINK_TOLERANCE) {
				$table_output .= "<span class=\"greyed\">...</span> ";
			}

			# Links
			for ($page_link_num = 1; $page_link_num <= $maximum_page; $page_link_num++) {

				# If within three of current page
				if ($page_link_num > $page_number - $PAGE_LINK_TOLERANCE && $page_link_num < $page_number + $PAGE_LINK_TOLERANCE) {

				
					if ($page_link_num == $page_number) {
						$table_output .= "<span class=\"activelink\"><strong>" . $page_link_num . "</strong></span> ";
					} else {
						$table_output .= "<span class=\"link\"><a href=\"javascript:pageTo(" . $page_link_num . ");\">" . $page_link_num . "</a></span> ";
					}
				}
			}

			# Indicate missing links
			if ($page_number < $maximum_page + 1 - $PAGE_LINK_TOLERANCE) {
				$table_output .= "<span class=\"greyed\">...</span> ";
			}

			# next
			if ($page_number < $maximum_page) {
				$table_output .= "<span class=\"link\"><a href=\"javascript:pageTo(" . ($page_number + 1) . ");\">next</a></span> ";
			}

			# Last
			if ($page_number < $maximum_page + 1 - $PAGE_LINK_TOLERANCE) {
				$table_output .= "<span class=\"link\"><a href=\"javascript:pageTo(" . $maximum_page . ");\"><strong>" . $maximum_page . "</strong></a></span> ";
			}

			# Dropdown
			$select_array = array();
			for ($i = 1; $i <= $maximum_page; $i++) {
				$select_array[] = $i;
			}
			$table_output .= " | Select Page: " . createSelector("selectpageresult", $select_array, $select_array, $page_number - 1, "selectPage();");

			# End paging
			$table_output .= "</p>";
		}
		
		$table_output .= "</div>";
		$table_output .= "</div>";

		# Return
		return $table_output;
	}

	/**
	 * drawBrowseTable() draws the browse table
	 *
	 * @param content_array is the content
	*/
	function drawSearchingTable($content_array = array(), $table_header = "Browsing", $group_field = "", $table_type = "users") {
		# Bring in some commonly used globals
		global $YES_NO_ARRAY;
		global $ADMIN_BROWSING_PAGE_RESULTS;
		global $PAGE_LINK_TOLERANCE;
		
		# Get page number of results
		$page_number = (@$_POST["result"]) ? $_POST["result"] : 1;

		# Get offset to start results at
		$result_offset = ($page_number - 1) * $ADMIN_BROWSING_PAGE_RESULTS;

		# Output to return
		$table_output = "";

		# Current value of grouping variable
		$group_value = null;

		# Count columns
		$column_count = 0;

		# Open table
		$table_output .= "<table class=\"admintable\" cellspacing=\"0\">";
		$table_output .= "<thead>";
		$table_output .= "<tr>";

		# Add main columns
		foreach ($this -> properties as $property_id => $property) {

			# If it's browse property is on...
			if ($property -> getData("tp_browsesortorder") != "0") {
				$table_output .= "<th>" . $property -> getData("tp_name") . "</th>";

				# Increment column count
				$column_count++;
			}
		}

		# Add custom columns
		foreach ($this -> custom_columns as $column_id => $column_data) {
			$table_output .= "<th>" . $column_data["name"] . "</th>";

			# Increment column count
			$column_count++;
		}

		# Close header
		$table_output .= "</tr>";
		$table_output .= "</thead>";
		
		$table_output .= "<tbody>";

		# Count rows to alternate colours
		$counter = 0;
	
		# For each row of content
		foreach ($content_array as $row_id => $row) {

			if ($counter >= $result_offset && $counter < $result_offset + $ADMIN_BROWSING_PAGE_RESULTS) {
				# Check group field
				if ($group_field != "") {
					if ($group_value != $row[$group_field]) {

						# Update value
						$group_value = $row[$group_field];

						# Draw
						$table_output .= "<tr class=\"rowsubheader\"><td colspan=\"" . $column_count . "\"><strong>" . $group_value . "</strong></td></tr>";
					}
				}

				# Display alternating row colours
				$table_output .= ($counter % 2 != 0) ? "<tr>" : "<tr class=\"alternate\">";

				# Add main columns
				foreach ($this -> properties as $property_id => $property) {

					if ($property -> getData("tp_browsesortorder") != "0") {

						$column_content = $this -> formatBrowse($row, $property -> getData("tp_browseformat"));

						$column_content = ($column_content == "") ? "&nbsp;" : $column_content;

						$table_output .= "<td>" . $column_content . "</td>";
					}
				}

				# Add custom columns
				foreach ($this -> custom_columns as $column_id => $column_data) {
					$table_output .= "<td>" . $this -> formatCustomColumn($column_data["value"], $row) . "</td>";
				}

				# Close row
				$table_output .= "</tr>";

			}

			# Increment counter for alternating row colours
			$counter++;
		}

		$table_output .= "</tbody>";
		$table_output .= "</table>";

		# Total number of pages
		$maximum_page = ceil(count($content_array) / $ADMIN_BROWSING_PAGE_RESULTS);

		# Paging
		$table_output .= "<div class=\"paging\">";
		
		# If paging required
		if ($maximum_page > 1) {

			$table_output .= "<p>Pages: ";

			# First
			if ($page_number > $PAGE_LINK_TOLERANCE) {
				$table_output .= "<span class=\"link\"><a href=\"javascript:pageTo(1);\"><strong>1</strong></a></span> ";
			}

			# previous
			if ($page_number > 1) {
				$table_output .= "<span class=\"link\"><a href=\"javascript:pageTo(" . ($page_number - 1) . ");\">prev</a></span> ";
			}
			
			# Indicate missing links
			if ($page_number > $PAGE_LINK_TOLERANCE) {
				$table_output .= "<span class=\"greyed\">...</span> ";
			}

			# Links
			for ($page_link_num = 1; $page_link_num <= $maximum_page; $page_link_num++) {

				# If within three of current page
				if ($page_link_num > $page_number - $PAGE_LINK_TOLERANCE && $page_link_num < $page_number + $PAGE_LINK_TOLERANCE) {

				
					if ($page_link_num == $page_number) {
						$table_output .= "<span class=\"activelink\"><strong>" . $page_link_num . "</strong></span> ";
					} else {
						$table_output .= "<span class=\"link\"><a href=\"javascript:pageTo(" . $page_link_num . ");\">" . $page_link_num . "</a></span> ";
					}
				}
			}

			# Indicate missing links
			if ($page_number < $maximum_page + 1 - $PAGE_LINK_TOLERANCE) {
				$table_output .= "<span class=\"greyed\">...</span> ";
			}

			# next
			if ($page_number < $maximum_page) {
				$table_output .= "<span class=\"link\"><a href=\"javascript:pageTo(" . ($page_number + 1) . ");\">next</a></span> ";
			}

			# Last
			if ($page_number < $maximum_page + 1 - $PAGE_LINK_TOLERANCE) {
				$table_output .= "<span class=\"link\"><a href=\"javascript:pageTo(" . $maximum_page . ");\"><strong>" . $maximum_page . "</strong></a></span> ";
			}

			# Dropdown
			$select_array = array();
			for ($i = 1; $i <= $maximum_page; $i++) {
				$select_array[] = $i;
			}
			$table_output .= " | Select Page: " . createSelector("selectpageresult", $select_array, $select_array, $page_number - 1, "selectPage();");

			# End paging
			$table_output .= "</p>";
		}

		# Return
		return $table_output;
	}

	/**
	 * generateInputForm() generates an add/edit form
	 *
	 * @param form_type is the type of form "add" or "edit"
	 * @param existing_data is the existing data for the add form
	 * @param edit_id is the ID of the item being editted in edit mode
	 * @param header_message is the message to use as a table header
	 * @param suppress_helpers is whether to suppress the helper icons
	 *
	 * @return the formatted ready-to-display form
	*/
	function generateInputForm($form_type = "add", $existing_data = array(), $edit_id = 0, $header_message = false, $suppress_helpers = false) {

		# Global
		global $PAGE_ID;
		global $type_name;

		# Form output
		$form_output = "";

		# Record hidden inputs to be placed at the end
		$hidden_inputs = array();
		# Generate form
		$form_output .= "<form name=\"" . $form_type . "inputform\" id=\"" . $form_type . "inputform\" action=\"" . $PAGE_ID . ".php\" method=\"post\">";
		
		# Hidden input vars
		$form_output .= "<input type=\"hidden\" name=\"mode\" id=\"mode\" value=\"" . $form_type . "\" />";
		$form_output .= "<input type=\"hidden\" name=\"id\" id=\"id\" value=\"" . $edit_id . "\" />";
		$form_output .= "<input type=\"hidden\" name=\"submitted\" id=\"submitted\" value=\"1\" />";
	
		if ($PAGE_ID == "adminproperties" && $form_type == "edit") {

			$form_output .= "<input type=\"hidden\" name=\"tp-table\" id=\"tp-table\" value=\"" . $existing_data["tp_table"] . "\" />";
			$form_output .= "<input type=\"hidden\" name=\"tp-field\" id=\"tp-field\" value=\"" . $existing_data["tp_field"] . "\" />";
		}

		# Open table
		$form_output .= "<table class=\"inputtable\" cellspacing=\"0\" width=\"80%\">";// 

		# Header
		if (!$header_message) {
			$form_output .= "<tr><th colspan=\"2\">" . (($form_type == "add") ? "Enter properties of new " . $type_name . ":" : "Edit properties of this " . $type_name . ":") . "</th></tr>";
		} else {
			$form_output .= "<tr><th colspan=\"2\">" . $header_message . "</th></tr>";
		}
		
		#the flag is used to judge the times for parent tree
		$flag_parent=false;
		# Add fields
		foreach ($this -> properties as $property_id => $property) {
			# Parse format
			$input_format = explode("|", $property -> getData("tp_requiredinput"));

			# Get name of input field to generate
			$input_field_name = preg_replace("/\_/", "-", $property -> getID());

			# Check whether this item should be INSERTed or UPDATEd
			if ($form_type == "add") {
				$use_field = ($property -> getData("tp_inserted") == "1");
			} else {
				$use_field = ($property -> getData("tp_updated") == "1");
			}

			# Check if input is required or optional
			$input_required = ($property -> getData("tp_required") == "1");

			# If using
			if ($use_field) {
				//echo "tp_name".$property -> getData("tp_name")."<br/>";
//				echo "input:".$input_field_name."<br/>";
//				echo "input_format:".$input_format[0]."<br/>";
				
				switch ($input_format[0]) {

					# 0 = hidden completely
					case "0":

						break;

					# 1 = regular text/password field
					case "1":

						# Get vars
						$field_size = $input_format[1];
						$default_value = $input_format[2];
						$is_password = ($input_format[3] == "true");
						$max_length = $input_format[4];
						$character_set = $input_format[5];

						# Evaluate default value
						if ($form_type == "add") {
							eval("$" . "default_value = " . $default_value . ";");

							# Check submission
							if (@$_POST[$input_field_name]) {
								$default_value = stripslashes($_POST[$input_field_name]);
							}
						} else {
							$default_value = $existing_data[$property -> getID()];
						}

						# Output
						$form_output .= "<tr>";
						$form_output .= "<td class=\"norightborder\">" . $this -> generateLabel($property -> getData("tp_name"), ($suppress_helpers ? false : $property -> getData("tp_description"))) . "</td>";
						$form_output .= "<td>";

						# Password or Text
						if ($is_password) {

							$form_output .= "<input type=\"password\" size=\"" . $field_size . "\" name=\"" . $input_field_name . "\" id=\"" . $input_field_name . "\" value=\"" . $default_value . "\" maxlength=\"" . $max_length . "\" />";

						} else {
						
						
							$form_output .= "<input type=\"text\" size=\"" . $field_size . "\" name=\"" . $input_field_name . "\" id=\"" . $input_field_name . "\" value=\"" . $default_value . "\" maxlength=\"" . $max_length . "\" />";
						}
						$form_output .= " " . (($input_required) ? $this -> generateRequiredIndicator() : "") . " " . (($property -> getData("tp_unique") == "1" && !$suppress_helpers) ? " " . $this -> generateUniqueIndicator() : "")  . "</td></tr>";

						# If password, have second row
						if ($is_password) {
							$form_output .= "<tr><td class=\"norightborder\">Confirm " . $property -> getData("tp_name") . ":</td><td>";

							$form_output .= "<input type=\"password\" size=\"" . $field_size . "\" name=\"" . $input_field_name . "-conf\" id=\"" . $input_field_name . "-conf\" value=\"" . $default_value . "\" maxlength=\"" . $max_length . "\" />";

							$form_output .= "</td></tr>";
						}


						# Break
						break;

					# 2 - date selector
					case "2":

						# Globals
						global $HOUR_ARRAY;
						global $YEAR_ARRAY;
						global $MONTH_NUM_ARRAY;
						global $MONTH_ARRAY;
						global $DAY_ARRAY;
						global $QUARTER_MINUTE_ARRAY;

						# Get vars
						$show_time = ($input_format[1] == "true");
						$default_value = $input_format[2];

						if ($form_type == "add") {
							eval("$" . "default_value = " . $default_value . ";");

							# Sort into sections
							$year = substr($default_value, 0, 4);
							$month = substr($default_value, 4, 2);
							$day = substr($default_value, 6, 2);
							$hour = substr($default_value, 8, 2);
							$minute = substr($default_value, 10, 2);
							$seconds = substr($default_value, 12, 2);

							# If POSTed
							if (@$_POST[$input_field_name . "-d"]) {
								$year = (@$_POST[$input_field_name . "-y"]) ? str_pad($_POST[$input_field_name . "-y"], 4, "0", STR_PAD_LEFT) : $year;
								$month = (@$_POST[$input_field_name . "-m"]) ? str_pad($_POST[$input_field_name . "-m"], 2, "0", STR_PAD_LEFT) : $month;
								$day = (@$_POST[$input_field_name . "-d"]) ? str_pad($_POST[$input_field_name . "-d"], 2, "0", STR_PAD_LEFT) : $day;
								$hour = (@$_POST[$input_field_name . "-th"]) ? str_pad($_POST[$input_field_name . "-th"], 2, "0", STR_PAD_LEFT) : $hour;
								$minute = (@$_POST[$input_field_name . "-tm"]) ? str_pad($_POST[$input_field_name . "-tm"], 2, "0", STR_PAD_LEFT) : $minute;
							}
						} else {
							$default_value = $existing_data[$property -> getID()];

							# Sort into sections
							$year = substr($default_value, 0, 4);
							$month = substr($default_value, 4, 2);
							$day = substr($default_value, 6, 2);
							$hour = substr($default_value, 8, 2);
							$minute = substr($default_value, 10, 2);
							$seconds = substr($default_value, 12, 2);
						}
						

						# Output
						$form_output .= "<tr><td class=\"norightborder\">" . $this -> generateLabel($property -> getData("tp_name"), ($suppress_helpers ? false : $property -> getData("tp_description"))) . "</td>";

						$form_output .= "<td>" . 
							createSelector($input_field_name . "-d", $DAY_ARRAY, $DAY_ARRAY, findInArray($DAY_ARRAY, $day)) .
							"" .
							createSelector($input_field_name . "-m", $MONTH_ARRAY, $MONTH_NUM_ARRAY, findInArray($MONTH_NUM_ARRAY, $month)) .
							"" .
							createSelector($input_field_name . "-y", $YEAR_ARRAY, $YEAR_ARRAY, findInArray($YEAR_ARRAY, $year));
						
						if ($show_time) {
							$form_output .= ", " .
								createSelector($input_field_name . "-th", $HOUR_ARRAY, $HOUR_ARRAY, findInArray($HOUR_ARRAY, $hour)) .
								":" .
								createSelector($input_field_name . "-tm", $QUARTER_MINUTE_ARRAY, $QUARTER_MINUTE_ARRAY, findInArray($QUARTER_MINUTE_ARRAY, $minute));
						}

						$form_output .= "</td></tr>";

						break;

					# 3 - select object
					case "3":

						# Get vars
						$select_names = $input_format[1];
						$select_values = $input_format[2];
						$default_value = $input_format[3];
						
						# Evaluate
						eval("$" . "select_names = " . $select_names . ";");
						eval("$" . "select_values = " . $select_values . ";");
						eval("$" . "default_value = " . $default_value . ";");

						# If a number, create numbers instead
						if ($select_values == "num") {

							$select_values = array();
							foreach ($select_names as $key => $value) {
								$select_values[] = $key;
							}
						}

						# If add mode, find index of default value
						if ($form_type == "add") {
							
							# Default
							$selected_index = 0;

							# For each value in the <select>...
							if (is_array($select_values)) {
								foreach ($select_values as $value_index => $select_value) {

									# If it matches
									if ("" . $select_value == "" . $default_value) {
										$selected_index = $value_index;
									}
								}
							}

							# If POSTed, get value
							if (@$_POST["submitted"]) {
								$selected_index = (integer) $_POST[$input_field_name];
							}

						# If in edit mode, find index of current value
						} else {

							# Default
							$selected_index = 0;

							# For each value in the <select>...
							foreach ($select_values as $value_index => $select_value) {
								
								# If it matches
								if ("" . $select_value == "" . $existing_data[$property -> getID()]) {
									$selected_index = $value_index;
								}
							}
						}

						# Output
						$form_output .= "<tr>";
						$form_output .= "<td class=\"norightborder\">" . $this -> generateLabel($property -> getData("tp_name"), ($suppress_helpers ? false : $property -> getData("tp_description"))) . "</td>";
						$form_output .= "<td>" . createSelector($input_field_name, $select_names, $select_values, $selected_index) . " " . (($input_required) ? $this -> generateRequiredIndicator() : "") . "</td>";
						$form_output .= "</tr>";

						# Break
						break;

					# 4 = regular multiline text field
					case "4":

						# Get vars
						$columns = $input_format[1];
						$rows = $input_format[2];
						$default_value = $input_format[3];
						$character_set = $input_format[4];

						# Evaluate default value
						if ($form_type == "add") {
							eval("$" . "default_value = " . $default_value . ";");

							# If POSTed, retrieve value
							if (@$_POST["submitted"]) {
								$default_value = stripslashes($_POST[$input_field_name]);
							}
						} else {
							$default_value = $existing_data[$property -> getID()];
						}

						# Output
						$form_output .= "<tr>";
						$form_output .= "<td colspan=\"2\">" . $this -> generateLabel($property -> getData("tp_name"), ($suppress_helpers ? false : $property -> getData("tp_description"))) . " " . (($input_required) ? $this -> generateRequiredIndicator() : "") . "<br /><br />";
						$form_output .= "<textarea name=\"" . $input_field_name . "\" id=\"" . $input_field_name . "\" rows=\"" . $rows . "\" cols=\"" . $columns . "\">" . $default_value . "</textarea>";
						if ($input_field_name == "tp-requiredinput") {
							$form_output .= "<br /><br /><input type=\"button\" value=\"Help Me\" onclick=\"helpRequiredInput();\" />";
						}
						
						$form_output .= "</td>";
						$form_output .= "</tr>";

						# Break
						break;

					# 5 - checkbox list
					case "5":

						# Get vars
						$checkbox_names = $input_format[1];
						$checkbox_values = $input_format[2];
						$default_value = $input_format[3];

						# Evaluate checkboxes
						eval("$" . "checkbox_names = " . $checkbox_names . ";");
						eval("$" . "checkbox_values = " . $checkbox_values . ";");

						# Evaluate default value
						if ($form_type == "add") {
							eval("$" . "default_value = " . $default_value . ";");

							# If posted
							if (@$_POST["submitted"]) {

								$default_value = "";

								foreach ($checkbox_names as $cb_id => $cb_text) {
									if (@$_POST[$input_field_name . "-" . $checkbox_values[$cb_id]]) {
										$default_value .= $checkbox_values[$cb_id] . ",";
									}
								}

								if (strlen($default_value) > 0) {
									$default_value = substr($default_value, 0, strlen($default_value) - 1);
								}
							}
						} else {
							$default_value = $existing_data[$property -> getID()];
						}

						# Divide default value into item values
						$default_value = explode(",", $default_value);

						# Output
						$form_output .= "<tr>";
						$form_output .= "<td class=\"norightborder\">" . $this -> generateLabel($property -> getData("tp_name"), ($suppress_helpers ? false : $property -> getData("tp_description"))) . "</td>";
						$form_output .= "<td>";
						foreach ($checkbox_names as $cb_id => $cb_text) {

							# Check whether it is checked
							$is_checked = false;
							foreach ($default_value as $value) {
								if ($checkbox_values[$cb_id] == $value) {
									$is_checked = true;
								}
							}

							$form_output .= "<input type=\"checkbox\"" . ($is_checked ? " checked=\"checked\"" : "") . " name=\"" . $input_field_name . "-" . $checkbox_values[$cb_id] . "\" id=\"" . $input_field_name . "-" . $checkbox_values[$cb_id] . "\" /> <label for=\"" . $input_field_name . "-" . $checkbox_values[$cb_id] . "\">" . $cb_text . "</label><br />";
						}
						$form_output .= "</td>";
						$form_output .= "</tr>";

						break;

					# 6 = Fixed value - ignore until form submitted
					case "6":
						break;

					# 7 = Boolean Yes/No selector
					case "7":

						# Vars
						$no_option = $input_format[1];
						$yes_option = $input_format[2];
						$default_value = $input_format[3];

						# Evaluate
						eval("$" . "no_option = " . $no_option . ";");
						eval("$" . "yes_option = " . $yes_option . ";");
						

						# Check default value
						if ($form_type == "add") {
							eval("$" . "default_value = " . $default_value . ";");

							# If POSTed
							if (@$_POST["submitted"]) {
								$default_value = (@$_POST[$input_field_name]) ? $_POST[$input_field_name] : 0;
							}
						} else {
							$default_value = $existing_data[$property -> getID()];
						}


						# Output
						$form_output .= "<tr>";
						$form_output .= "<td class=\"norightborder\">" . $this -> generateLabel($property -> getData("tp_name"), ($suppress_helpers ? false : $property -> getData("tp_description"))) . "</td>";
						$form_output .= "<td>" . createRadioButtonPair($input_field_name, $no_option, $yes_option, $default_value) . "</td>";
						$form_output .= "</tr>";

						break;

					# 8 - custom input
					case "8":
						
						# Input
						$custom_input = $input_format[1];
						
						//echo "getID:".$property -> getID();
						//echo ":".$existing_data[$property -> getID()]."<br/>";
						
						# Evaluate
						//eval("$" . "custom_input = " . $custom_input . ";");
						//echo "1"."</br>";
						

						if($form_type=="edit"){						
							
							if($flag_parent==false){
								$function="generatePageSelectFlashInput('".$existing_data["p_parent"]."','".$existing_data["p_section"]."')";
								$flag_parent=true;
								eval("$" . "custom_input = " .$function. ";");
							}
						
						}
						else{
							eval("$" . "custom_input = " . $custom_input . ";");
						}
						
						# Output
						$form_output .= $custom_input;

						# End
						break;

					# 9 - file selector
					case "9":

						# Can it be empty
						$can_be_empty = ($input_format[1] == "true");

						# Get list of uploaded files
						$uploaded_files = getFiles("../assets/uploads/");

						# If it can be empty, add an empty item
						if ($can_be_empty) {
							array_unshift($uploaded_files, "");
						}

						# If add mode, find index of default value
						if ($form_type == "add") {
							
							# Default
							$selected_index = 0;

							# If POSTed
							if (@$_POST["submitted"]) {
								$selected_index = (@$_POST[$input_field_name]) ? $_POST[$input_field_name] : 0;
							}

						# If in edit mode, find index of current value
						} else {

							# Default
							$selected_index = 0;

							# For each value in the <select>...
							foreach ($uploaded_files as $file_index => $file_value) {
								
								# If it matches
								if ("" . $file_value == "" . $existing_data[$property -> getID()]) {
									$selected_index = $file_index;
								}
							}
						}

						# Output
						$form_output .= "<tr>";
						$form_output .= "<td class=\"norightborder\">" . $this -> generateLabel($property -> getData("tp_name"), ($suppress_helpers ? false : $property -> getData("tp_description"))) . "</td>";
						$form_output .= "<td>" . createSelector($input_field_name, $uploaded_files, $uploaded_files, $selected_index) . " " . (($input_required) ? $this -> generateRequiredIndicator() : "") . "</td>";
						$form_output .= "</tr>";

					# 10 - image
					case "10":

						# Output
						$form_output .= "<tr>";
						$form_output .= "<td class=\"norightborder\">" . $this -> generateLabel($property -> getData("tp_name"), ($suppress_helpers ? false : $property -> getData("tp_description"))) . "</td>";

						if ($form_type == "add") {
							$default_value = "";
							$default_alt = "";
							$default_caption = "";
						} else {
							$default_value = explode("|", $existing_data[$property -> getID()]);
							$default_alt = @$default_value[1];
							$default_caption = @$default_value[2];
							$default_value = $default_value[0];
						}

						# Image selector
						$form_output .= "<td>" .
							"<p><input type=\"text\" size=\"30\" name=\"" . $input_field_name . "-image\" id=\"" . $input_field_name . "-image\" value=\"" . $default_value . "\" /> <input type=\"button\" value=\"Select\" onclick=\"openSelectUploadedImageWin('" . $input_field_name . "-image');\" /> " . (($input_required) ? $this -> generateRequiredIndicator() : "") . " " . (($property -> getData("tp_unique") == "1") ? " " . $this -> generateUniqueIndicator() : "") .
							"</p><p>Alt Tag: <input type=\"text\" size=\"30\" name=\"" . $input_field_name . "-alt\" id=\"" . $input_field_name . "-alt\" value=\"" . $default_alt . "\" /></p>" .
							"<p>Caption: <input type=\"text\" size=\"30\" name=\"" . $input_field_name . "-caption\" id=\"" . $input_field_name . "-caption\" value=\"" . $default_caption . "\" /></p>";

						# Close
						$form_output .= "</td></tr>";

						break;
					
					#11 -math text
					case "11":

						# Get vars
						$columns = $input_format[1];
						$rows = $input_format[2];
						$default_value = $input_format[3];
						$character_set = $input_format[4];

						# Evaluate default value
						if ($form_type == "add") {
							eval("$" . "default_value = " . $default_value . ";");

							# If POSTed, retrieve value
							if (@$_POST["submitted"]) {
								$default_value = stripslashes($_POST[$input_field_name]);
							}
						} else {
							$default_value = $existing_data[$property -> getID()];
						}

						# Output
						$form_output .= "<tr>";
						$form_output .= "<td colspan=\"2\">" . $this -> generateLabel($property -> getData("tp_name"), ($suppress_helpers ? false : $property -> getData("tp_description"))) . " " . (($input_required) ? $this -> generateRequiredIndicator() : "") . "<br /><br />";
						$form_output .= "<a href=\"javascript:ShowPanel('math');\">Math</a><br>";
						$form_output .= "<div id=\"math\" style=\"display: none;left: 120px; top: 90px; width: 80%; padding: 15px;\">";//
						
						#Add symbol
						for($i=915;$i<=937;$i++){
							if($i!=930){
							$form_output .= "<a href=\"javascript:addSymbolIn('"."&#".$i.";"."','". $input_field_name ."');\">"."&#".$i.";"."</a>&nbsp;";
							}			
						}
						$form_output .="<br/>";
						for($j=945;$j<=969;$j++){
							$form_output .= "<a href=\"javascript:addSymbolIn('"."&#".$j.";"."','". $input_field_name ."');\">"."&#".$j.";"."</a>&nbsp;";
							
						}
						$form_output .="<br/>";
						$form_output .= "<a href=\"javascript:addSymbolIn('"."&#977;"."','". $input_field_name ."');\">"."&#977;"."</a>&nbsp;";
						$form_output .= "<a href=\"javascript:addSymbolIn('"."&#978;"."','". $input_field_name ."');\">"."&#978;"."</a>&nbsp;";
						$form_output .= "<a href=\"javascript:addSymbolIn('"."&#982;"."','". $input_field_name ."');\">"."&#982;"."</a>&nbsp;";
						
						$form_output .="</div><br>";
						$form_output .= "<textarea name=\"" . $input_field_name . "\" id=\"" . $input_field_name . "\" rows=\"" . $rows . "\" cols=\"" . $columns . "\">" . $default_value . "</textarea>";
						if ($input_field_name == "tp-requiredinput") {
							$form_output .= "<br /><br /><input type=\"button\" value=\"Help Me\" onclick=\"helpRequiredInput();\" />";
						}
						
						$form_output .= "</td>";
						$form_output .= "</tr>";

						# Break
						break;			
								
					# 12 = regular text/password field for glossary
					case "12":

						# Get vars
						$field_size = $input_format[1];
						$default_value = $input_format[2];
						$is_password = ($input_format[3] == "true");
						$max_length = $input_format[4];
						$character_set = $input_format[5];

						# Evaluate default value
						if ($form_type == "add") {
							eval("$" . "default_value = " . $default_value . ";");

							# Check submission
							if (@$_POST[$input_field_name]) {
								$default_value = stripslashes($_POST[$input_field_name]);
							}
						} else {
							$default_value = $existing_data[$property -> getID()];
						}

						# Output
						$form_output .= "<tr>";
						$form_output .= "<td class=\"norightborder\">" . $this -> generateLabel($property -> getData("tp_name"), ($suppress_helpers ? false : $property -> getData("tp_description"))) . "</td>";
						$form_output .= "<td>";

						# Password or Text
						if ($is_password) {

							$form_output .= "<input type=\"password\" size=\"" . $field_size . "\" name=\"" . $input_field_name . "\" id=\"" . $input_field_name . "\" value=\"" . $default_value . "\" maxlength=\"" . $max_length . "\" />";

						} else {
						
						
							$form_output .= "<input type=\"text\" size=\"" . $field_size . "\" name=\"" . $input_field_name . "\" id=\"" . $input_field_name . "\" value=\"" . $default_value . "\" maxlength=\"" . $max_length . "\" />";
						}
						$form_output .= " " . (($input_required) ? $this -> generateRequiredIndicator() : "") . " " . (($property -> getData("tp_unique") == "1" && !$suppress_helpers) ? " " . $this -> generateUniqueIndicator() : "")  . "</td></tr>";

						# If password, have second row
						if ($is_password) {
							$form_output .= "<tr><td class=\"norightborder\">Confirm " . $property -> getData("tp_name") . ":</td><td>";

							$form_output .= "<input type=\"password\" size=\"" . $field_size . "\" name=\"" . $input_field_name . "-conf\" id=\"" . $input_field_name . "-conf\" value=\"" . $default_value . "\" maxlength=\"" . $max_length . "\" />";

							$form_output .= "</td></tr>";
						}


						# Break
						break;
						
					default:

						$form_output .= "<tr><td colspan=\"2\">Sorry, no handler available for <em>" . $property -> getData("tp_name") . "</em></td></tr>";
				}
			}
		}

		# Add a Submit button
		$form_output .= "<tr>";
		$form_output .= "<td colspan=\"2\" style=\"text-align: right;\">";
		if ($form_type == "add") {
			$form_output .= "<input type=\"reset\" value=\"Clear\" class=\"savebutton\" /> ";
		}
		$form_output .= "<input class=\"savebutton\" type=\"submit\" value=\"" . (($form_type == "add") ? "Save" : "Save Changes") . "\" /></td>";
		$form_output .= "</tr>";

		$form_output .= "</table>";

		# Print hidden inputs
		foreach ($hidden_inputs as $input) {
			$form_output .= $input;
		}

		# Close form to finish
		$form_output .= "</form>";

		# Return
		return $form_output;
	}

	/**
	 * generateLabel() generates a label for the input form
	 *
	 * @param field_name is the name of the field
	 * @param field_description is the description
	 *
	 * @return the formatted text
	*/
	function generateLabel($field_name = "", $field_description = "") {

		# Name
		$output = $field_name . ":";
		
		# Help icon if description provided
		$output .= ($field_description != "") ? " <span class=\"helpicon\" title=\"" . $field_description . "\">&nbsp;?&nbsp;</span>" : "";

		# Return
		return $output;
	}

	/**
	 * generateRequiredIndicator() generates a required indicator
	*/
	function generateRequiredIndicator() {
		
		return "<span class=\"required\" title=\"Field Required\">&nbsp;!&nbsp;</span>";
	}

	/**
	 * generateUniqueIndicator() generates a unique indicator
	*/
	function generateUniqueIndicator() {

		return "<span class=\"unique\" title=\"Unique\">&nbsp;U&nbsp;</span>";
	}


	/**
	 * attemptToSave() attempts to retrieve data from POST and INSERT or UPDATE it
	 *
	 * @param save_mode is the mode, "add" or "edit"
	 * @param index_field is the Key field used in the WHERE clause when updating
	 * @param index_numeric is whether the index key is a number or a string
	 * @param item_id is the ID of the item to update if in edit mode
	*/
	function attemptToSave($save_mode = "add", $index_field = "", $index_numeric = true, $item_id = 0) {

		# Globals
		global $PROJECT_DB_TABLES;
		global $PROPERTY_TYPE_DB_ARRAY;
		global $PASSED_ID;
		global $VALID_CHAR_LIST;
		global $USER;
		global $PAGE_ID;

		# Maintain list of errors within the attempted registration
		$error_array = array();

		# List of items that must be unique, and their proposed values
		$unique_array = array();

		# SQL INSERT pairs
		$sql_insert_array = array();

		# Table name
		$table_name = "";

		# If adding/editing a Table Property, have to do an ALTER as well
		$alter_field_table = "";
		$alter_field_name = "";

		# Get data from POST
		foreach ($this -> properties as $property_id => $property) {

			# Store table name
			$table_name = $property -> getData("tp_table");

			# Parse format
			$input_format = explode("|", $property -> getData("tp_requiredinput"));

			# Get name of POST field to get data from
			$input_field_name = preg_replace("/\_/", "-", $property -> getID());

			# If adding a table property, store field name, type, required, and table
			if ($table_name == $PROJECT_DB_TABLES["table_properties"]) {
				$alter_field_table = ($input_field_name == "tp-table") ? @$_POST[$input_field_name] : $alter_field_table;
				$alter_field_name = ($input_field_name == "tp-field") ? @$_POST[$input_field_name] : $alter_field_name;
			}

			# Check if INSERTing a string or number
			$is_string = ($property -> getData("tp_type") == "3" || $property -> getData("tp_type") == "4");

			# Check whether this item should be INSERTed or UPDATEd
			if ($save_mode == "add") {
				$use_field = ($property -> getData("tp_inserted") == "1");
			} else {
				$use_field = ($property -> getData("tp_updated") == "1");
			}
			
			# If using
			if ($use_field) {

				# Handle input types
				switch ($input_format[0]) {

					# Ignored
					case "0":

						# Ignored
						$sql_insert_array[$property -> getID()] = "Ignored";

						break;

					# Input text/password field
					case "1":

						# Get post data
						$output = trim(@$_POST[$input_field_name]);

						# Get required Chars
						$required_input = explode("|", $property -> getData("tp_requiredinput"));
						$input_format = $required_input[5];

						# Check if password
						$is_password = ($required_input[3] == "true");

						# Parse for OK chars
						if ($input_format != "any" && is_array($VALID_CHAR_LIST[$input_format])) {
							if (!containsValidChars(strtolower($output), $VALID_CHAR_LIST[$input_format])) {
								$error_array[] = $property -> getData("tp_name") . " contains invalid characters.";
							}
						}

						# Check if allowed to be empty
						if ($property -> getData("tp_required") == "1") {
							if ($output == "") {
								$error_array[] = $property -> getData("tp_name") . " must be set.";
							}
						}

						# Check for password
						if ($is_password) {

							# Get second
							$output_confirm = @$_POST[$input_field_name . "-conf"];
							
							# Compare
							if ($output != $output_confirm) {
								$error_array[] = $property -> getData("tp_name") . ": The two password fields must match.";
							}

							# Convert to MD5
							$output = md5($output);
						}

						# If a page ID, lowercase it
						if ($property -> getID() == "p_id") {
							$output = strtolower($output);
						}

						# Append to sql insert array
						$sql_insert_array[$property -> getID()] = ($is_string ? "\"" : "") . $output . ($is_string ? "\"" : "");

						# Check if this field is required to be unique, and if so check it
						if ($property -> getData("tp_unique") == "1") {
							
							# Add
							$unique_array[$property -> getID()] = array($output, $is_string);
						}

						# End
						break;

					# Date
					case "2":

						# Get post Data
						$year = @$_POST[$input_field_name . "-y"];
						$month = @$_POST[$input_field_name . "-m"];
						$day = @$_POST[$input_field_name . "-d"];
						$hour = (@$_POST[$input_field_name . "-th"]) ? $_POST[$input_field_name . "-th"] : "00";
						$minute = (@$_POST[$input_field_name . "-tm"]) ? $_POST[$input_field_name . "-tm"] : "00";

						# Construct output
						$output = $year . $month . $day . $hour . $minute . "00";

						# Append to SQL insert array
						$sql_insert_array[$property -> getID()] = ($is_string ? "\"" : "") . $output . "00" . ($is_string ? "\"" : "");

						# Check if this field is required to be unique, and if so check it
						if ($property -> getData("tp_unique") == "1") {
							
							# Add
							$unique_array[$property -> getID()] = array($output, $is_string);
						}

						break;

					# Select field
					case "3":

						# Get post data
						$output = @$_POST[$input_field_name];

						# Append to array
						$sql_insert_array[$property -> getID()] = ($is_string ? "\"" : "") . $output . ($is_string ? "\"" : "");

						# Check if this field is required to be unique, and if so check it
						if ($property -> getData("tp_unique") == "1") {
							
							# Add
							$unique_array[$property -> getID()] = array($output, $is_string);
						}

						# End
						break;

					# Multi-line text field
					case "4":
						
						# Get post data
						$output = (@$_POST[$input_field_name]) ? $_POST[$input_field_name] : "";

						# Get required Chars
						$input_format = explode("|", $property -> getData("tp_requiredinput"));
						$input_format = $input_format[4];

						# Parse for OK chars
						if ($input_format != "any" && is_array($VALID_CHAR_LIST[$input_format])) {
							if (!containsValidChars(strtolower($output), $VALID_CHAR_LIST[$input_format])) {
								$error_array[] = $property -> getData("tp_name") . " contains invalid characters.";
							}
						}

						# Check if allowed to be empty
						if ($property -> getData("tp_required") == "1") {
							if ($output == "") {
								$error_array[] = $property -> getData("tp_name") . " must be set.";
							}
						}

						# Append
						$sql_insert_array[$property -> getID()] = ($is_string ? "\"" : "") . $output . ($is_string ? "\"" : "");

						# Check if this field is required to be unique, and if so check it
						if ($property -> getData("tp_unique") == "1") {
							
							# Add
							$unique_array[$property -> getID()] = array($output, $is_string);
						}

						# Break
						break;

					# Checkbox list
					case "5":
						# Output array
						$output = array();

						# Parse input
						$input_format = explode("|", $property -> getData("tp_requiredinput"));
						eval("$" . "input_format = " . $input_format[2] . ";");

						# Check POST
						foreach ($input_format as $input_value) {
							if (@$_POST[$input_field_name . "-" . $input_value]) {
								$output[] = $input_value;
							} 
							else {
							}
						}

						# Group-related fields
						$group_related_field_ids = array("p_access", "ng_groups");
						$group_related_field_indexes = array("p_id", "ng_id");
						$group_related_field_numeric_indexes = array(false, true);

						# If in the p_access field of the pages table, need to take special action to ensure any groups that
						# that cannot be edited by this user are not overwritten
						$group_related_index = array_search($property -> getID(), $group_related_field_ids);
						if ($group_related_index !== false) {

							# If adding, get full list of groups
							if ($save_mode == "add") {

								$group_array = getRecord("SELECT g_id FROM " . $PROJECT_DB_TABLES["groups"]);
								$group_array = extractColumnFromArray($group_array, "g_id");

							# If editing, get current groups for this item
							} else {

								$group_array = getRecord("SELECT " . $property -> getID() . " FROM " . $property -> getData("tp_table") . " WHERE " . $group_related_field_indexes[$group_related_index] . " = " . ($group_related_field_numeric_indexes[$group_related_index] ? "" : "'") . $PASSED_ID . ($group_related_field_numeric_indexes[$group_related_index] ? "" : "'"));

								$group_array = explode(",", $group_array[0][$property -> getID()]);
							}

							# Groups that can be defined by users
							$user_definable_groups = $USER -> getEditableGroups();
							$user_definable_groups[] = 0;

							# Remove from group_array any items that can be defined by user
							$group_array = array_diff($group_array, $user_definable_groups);

							# Append to end of output
							$output = array_unique(array_merge($output, $group_array));
						}
						# Implode Output
						if($PAGE_ID!="adminusers"){
							
								$output = implode(",", $output);
						}
						else{
							if(count($output)==0){
								
								$error_array[] = $property -> getData("tp_name") . " must be set.";
							}
							else{
							
								$developerFlag=false;
								
								$administratorFlag=false;
								
								foreach($output as $key=>$value){
									
									if($value=="3"){
										
										$developerFlag=true;
									}
									if($value=="2"){
										
										$administratorFlag=true;
									}				
								}
								if($developerFlag==true){
									
									$output="3";
								}
								else if($developerFlag==false&&$administratorFlag==true){
									
									$output="2";
								}
								else if($developerFlag==false&&$administratorFlag==false){
									
									$output = implode(",", $output);
								}
							}
						}
						
						# Append
						$sql_insert_array[$property -> getID()] = ($is_string ? "\"" : "") . $output . ($is_string ? "\"" : "");
						# Check if this field is required to be unique, and if so check it
						if ($property -> getData("tp_unique") == "1") {
							
							# Add
							$unique_array[$property -> getID()] = array($output, $is_string);
						}

						# End
						break;

					# Fixed value
					case "6":

						# Get value
						$output = $input_format[1];

						# Evaluate value
						eval("$" . "output = " . $output . ";");

						# Add
						$sql_insert_array[$property -> getID()] = ($is_string ? "\"" : "") . $output . ($is_string ? "\"" : "");

						# Check if this field is required to be unique, and if so check it
						if ($property -> getData("tp_unique") == "1") {
							
							# Add
							$unique_array[$property -> getID()] = array($output, $is_string);
						}

						# End
						break;

					# Boolean Yes/No
					case "7":

						# Get value
						$output = (@$_POST[$input_field_name]) ? $_POST[$input_field_name] : "0";

						# If Can Lock Pages, ensure value is already set
						if ($property -> getID() == "g_can_lock") {
							if ((integer) $USER -> getCanLock() != 0) {
							
								# Append to array
								$sql_insert_array[$property -> getID()] = ($is_string ? "\"" : "") . $output . ($is_string ? "\"" : "");
		
								# Check if this field is required to be unique, and if so check it
								if ($property -> getData("tp_unique") == "1") {
									
									# Add
									$unique_array[$property -> getID()] = array($output, $is_string);
								}
							}
						} else if ($property -> getID() == "g_can_approve") {
							if ((integer) $USER -> getCanApprove() != 0) {
							
								# Append to array
								$sql_insert_array[$property -> getID()] = ($is_string ? "\"" : "") . $output . ($is_string ? "\"" : "");
		
								# Check if this field is required to be unique, and if so check it
								if ($property -> getData("tp_unique") == "1") {
									
									# Add
									$unique_array[$property -> getID()] = array($output, $is_string);
								}
							}
						} else {
						
							# Append to array
							$sql_insert_array[$property -> getID()] = ($is_string ? "\"" : "") . $output . ($is_string ? "\"" : "");
	
							# Check if this field is required to be unique, and if so check it
							if ($property -> getData("tp_unique") == "1") {
								
								# Add
								$unique_array[$property -> getID()] = array($output, $is_string);
							}
						}

						# End
						break;

					# Custom - assume a hidden input
					case "8":
						# Get value
						$output = (@$_POST[$input_field_name]) ? $_POST[$input_field_name] : "";
						# Append to array
						$sql_insert_array[$property -> getID()] = ($is_string ? "\"" : "") . $output . ($is_string ? "\"" : "");

						break;

					# file selector
					case "9":

						# Get value
						$output = (@$_POST[$input_field_name]) ? $_POST[$input_field_name] : "";

						# Append to array
						$sql_insert_array[$property -> getID()] = ($is_string ? "\"" : "") . $output . ($is_string ? "\"" : "");

						break;

					# Image  selector
					case "10":

						# Get values
						$file_name = (@$_POST[$input_field_name . "-image"]) ? $_POST[$input_field_name . "-image"] : "";
						$alt_tag = (@$_POST[$input_field_name . "-alt"]) ? $_POST[$input_field_name . "-alt"] : "";
						$caption = (@$_POST[$input_field_name . "-caption"]) ? $_POST[$input_field_name . "-caption"] : "";

						# Compile
						$output = $file_name . "|" . $alt_tag . "|" . $caption;

						# Append to array
						$sql_insert_array[$property -> getID()] = ($is_string ? "\"" : "") . $output . ($is_string ? "\"" : "");

						break;
					# Multi-line text field for glossary
					case "11":
						
						# Get post data
						$output = (@$_POST[$input_field_name]) ? $_POST[$input_field_name] : "";
						
						$output=$this->replaceMessyCode($output);
						//$output=str_replace("","",$output);
//						$output=str_replace("","",$output);
//						$output=str_replace("","",$output);
//						$output=str_replace("","",$output);
						# Get required Chars
						$input_format = explode("|", $property -> getData("tp_requiredinput"));
						$input_format = $input_format[4];

						# Parse for OK chars
						if ($input_format != "any" && is_array($VALID_CHAR_LIST[$input_format])) {
							if (!containsValidChars(strtolower($output), $VALID_CHAR_LIST[$input_format])) {
								$error_array[] = $property -> getData("tp_name") . " contains invalid characters.";
							}
						}

						# Check if allowed to be empty
						if ($property -> getData("tp_required") == "1") {
							if ($output == "") {
								$error_array[] = $property -> getData("tp_name") . " must be set.";
							}
						}

						# Append
						$sql_insert_array[$property -> getID()] = ($is_string ? "\"" : "") . $output . ($is_string ? "\"" : "");

						# Check if this field is required to be unique, and if so check it
						if ($property -> getData("tp_unique") == "1") {
							
							# Add
							$unique_array[$property -> getID()] = array($output, $is_string);
						}

						# Break
						break;
						
					# Input text/password field for glossary
					case "12":

						# Get post data
						$output = trim(@$_POST[$input_field_name]);
						
						$output=$this->replaceMessyCode($output);

						# Get required Chars
						$required_input = explode("|", $property -> getData("tp_requiredinput"));
						$input_format = $required_input[5];

						# Check if password
						$is_password = ($required_input[3] == "true");

						# Parse for OK chars
						if ($input_format != "any" && is_array($VALID_CHAR_LIST[$input_format])) {
							if (!containsValidChars(strtolower($output), $VALID_CHAR_LIST[$input_format])) {
								$error_array[] = $property -> getData("tp_name") . " contains invalid characters.";
							}
						}

						# Check if allowed to be empty
						if ($property -> getData("tp_required") == "1") {
							if ($output == "") {
								$error_array[] = $property -> getData("tp_name") . " must be set.";
							}
						}

						# Check for password
						if ($is_password) {

							# Get second
							$output_confirm = @$_POST[$input_field_name . "-conf"];
							
							# Compare
							if ($output != $output_confirm) {
								$error_array[] = $property -> getData("tp_name") . ": The two password fields must match.";
							}

							# Convert to MD5
							$output = md5($output);
						}

						# If a page ID, lowercase it
						if ($property -> getID() == "p_id") {
							$output = strtolower($output);
						}

						# Append to sql insert array
						$sql_insert_array[$property -> getID()] = ($is_string ? "\"" : "") . $output . ($is_string ? "\"" : "");

						# Check if this field is required to be unique, and if so check it
						if ($property -> getData("tp_unique") == "1") {
							
							# Add
							$unique_array[$property -> getID()] = array($output, $is_string);
						}

						# End
						break;
				}
			}
		}

		# Run uniqueness check
		if (count($unique_array) > 0) {

			# Construct SQL
			$sql = "SELECT " . implode(", ", array_keys($unique_array)) . " FROM " . $property -> getData("tp_table") . " WHERE ";
			foreach ($unique_array as $unique_field => $unique_value) {
				$sql .= $unique_field . " = " . ($unique_value[1] ? "\"" : "") . $unique_value[0] . ($unique_value[1] ? "\"" : "") . " AND ";
			}

			# Remove last 'and'
			$sql = substr($sql, 0, strlen($sql) - 5);

			# Results
			$results = getRecord($sql);

			# If in edit mode, get original data to compare against
			if ($save_mode == "edit") {

				$orig_results = getRecord($sql = "SELECT " . implode(", ", array_keys($unique_array)) . " FROM " . $property -> getData("tp_table") . " WHERE " . $index_field . " = " . ($index_numeric ? "" : "\"") . $PASSED_ID . ($index_numeric ? "" : "\""));
			}

			# If in save mode, just ensure no results were found
			if ($save_mode == "add") {

				if ($results !== false && count($results) > 0) {

					# Add error
					$error_array[] = "Duplicate values detected. The following fields must be unique: " . implode(", ", array_keys($unique_array));
				}

			# If in edit mode, ensure no results are found that aren't the initial values
			} else {
				if (count($results) > 0) {

					# ID has changed from original
					$unique_id_changed = false;

					# Check to see if Unique ID has changed
					foreach ($unique_array as $unique_field => $unique_value) {
						if ($results[0][$unique_field] != $orig_results[0][$unique_field]) {
							$unique_id_changed = true;
						}
					}

					# If unique ID has changed, and we're still getting a result, must be trying to overwrite another existing ID
					if ($unique_id_changed) {
					
						# Add error
						$error_array[] = "Duplicate values detected. The following fields must be unique: " . implode(", ", array_keys($unique_array));
					}
				} else {

					# No results, we're all good
				}
			}
		}

		# If no errors have occured thus far
		if (count($error_array) == 0) {

			# Construct SQL
			if ($save_mode == "add") {

				$saved_ok_message = "<p>OK, new item was added successfully.</p>";
				$saved_fail_message = "<p>Sorry, an error occured and the new item could not be added. Please try adding again.</p>";

				# SQL
				$sql = "INSERT INTO " . $table_name . " (" . implode(", ", array_keys($sql_insert_array)) . ") VALUES (" . implode(", ", $sql_insert_array) . ");";
				
				//echo "table_name:".$table_name."<br/>";
				//print_r($sql_insert_array);
				
				

				# Execute
				if (executeSQLQuery($sql, false)) {
					
					if($table_name=='apollo_pages'){
						//echo "@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@".$sql_insert_array["p_parent"]."<br/>";
						if($sql_insert_array["p_parent"] == "\"blog\""){
						//echo "###############################################"."<br/>";
							$sql_blogs = "INSERT INTO " .$PROJECT_DB_TABLES["blogs"]. " (b_id,b_date,b_tooltip) VALUES (".$sql_insert_array["p_id"].",1,\"\");";
						
							executeSQLQuery($sql_blogs, false);
						}
					}
					# Log
					logAddedItem($table_name, $unique_array);

					# If table properties, add column to desired table as well
					if ($table_name == $PROJECT_DB_TABLES["table_properties"]) {

						$table = preg_replace("/\"/", "", $sql_insert_array["tp_table"]);
						$field = preg_replace("/\"/", "", $sql_insert_array["tp_field"]);
						$field_type = preg_replace("/\"/", "", $sql_insert_array["tp_type"]);
						$required = preg_replace("/\"/", "", $sql_insert_array["tp_required"]);

						$sql2 = "ALTER TABLE " . $table . " ADD " . $field . " " . $PROPERTY_TYPE_DB_ARRAY[$field_type] . " " . (($required == "1") ? "NOT NULL " : "") . (($field_type == "1") ? "AUTO_INCREMENT" : "");

						if (executeSQLQuery($sql2, false)) {
							addMessage($saved_ok_message);
						} else {
							addMessage($saved_fail_message, 2);
						}

					# If pages, create file as well
					} else if ($table_name == $PROJECT_DB_TABLES["pages"]) {

						# Get ID and section with quotes removed
						$page_id = preg_replace("/\"/", "", $sql_insert_array["p_id"]);
						$page_section = preg_replace("/\"/", "", $sql_insert_array["p_section"]);

						# Try to create
						if (createContentFile($page_section, $page_id)) {

							addMessage($saved_ok_message);
						} else {

							addMessage($saved_fail_message, 2);
						}

					# If a group, add this group to list of currently editable groups for logged in user
					} else if ($table_name == $PROJECT_DB_TABLES["groups"]) {

						# Get ID of group that was added
						$new_group_id = getLastInsertedID();

						# Get ID of group that was justed added - go the long way
						$sql2 = "SELECT g_id FROM " . $PROJECT_DB_TABLES["groups"] . " WHERE g_name = " . $sql_insert_array["g_name"];

						$new_group_id = getRecord($sql2);

						if (count($new_group_id) == 1) {

							# Get group ID
							$new_group_id = $new_group_id[0]["g_id"];

							# Get currently editable groups
							$currently_editable_groups = $USER -> getEditableGroups();

							# Append this group
							$currently_editable_groups[] = $new_group_id;

							# Update database
							$sql2 = "UPDATE " . $PROJECT_DB_TABLES["groups"] . " SET g_priviledges = '" . implode(",", $currently_editable_groups) . "' WHERE g_id = " . $USER -> getGroup();

							if (executeSQLQuery($sql2, false)) {

								# Update currently editable groups
								$USER -> setEditableGroups($currently_editable_groups);

							} else {
								addMessage("<p>An error occured and the new group could not be made editable for your current group</p>", 2);
							}
						}

						addMessage($saved_ok_message);

					# Otherwise, we're all good
					} else {
						addMessage($saved_ok_message);
					}

				# SQL Error occured
				} else {
					addMessage($saved_fail_message, 2);
				}

				
			} else {

				$saved_ok_message = "<p>OK, changes were saved successfully.</p>";
				$saved_fail_message = "<p>Sorry, an error occured and the item could not be changed. Please try saving again.</p>";

				# SQL
				$sql = "UPDATE " . $table_name . " SET ";
				foreach ($sql_insert_array as $field_name => $field_value) {
					$sql .= $field_name . " = " . $field_value . ", ";
				}
				$sql = substr($sql, 0, strrpos($sql, ", "));
				$sql .= " WHERE " . $index_field . " = " . ($index_numeric ? "" : "\"") . $item_id . ($index_numeric ? "" : "\"");
				
				

				# If the UPDATE went OK
				if (executeSQLQuery($sql)) {
					
					if($table_name=='apollo_pages'){
					
						$sql_blogs = "UPDATE " .$PROJECT_DB_TABLES["blogs"]. " SET  b_id = ".$sql_insert_array["p_id"]." WHERE b_id = \"".$item_id."\";";
						
						executeSQLQuery($sql_blogs);
					}
					# Log
					logModifiedItem($table_name, $item_id);

					# If table properties, alter the table structure as well
					if ($table_name == $PROJECT_DB_TABLES["table_properties"]) {

						$field_type = preg_replace("/\"/", "", $sql_insert_array["tp_type"]);
						$required = preg_replace("/\"/", "", $sql_insert_array["tp_required"]);

						$table = $alter_field_table;
						$field = $alter_field_name;

						$sql2 = "ALTER TABLE " . $table . " MODIFY " . $field . " " . $PROPERTY_TYPE_DB_ARRAY[$field_type] . " " . (($required == "1") ? "NOT NULL " : "") . (($field_type == "1") ? "AUTO_INCREMENT" : "");

						if (executeSQLQuery($sql2)) {
							addMessage($saved_ok_message);
						} else {
							addMessage($saved_fail_message, 2);
						}
					
					# If pages, remove old file and file as well
					} else if ($table_name == $PROJECT_DB_TABLES["pages"]) {

						# Remove old file by deleting any files with the correct ID from any available directories
						$available_sections = getSectionNames();
						foreach ($available_sections as $section) {
							if (file_exists("../" . $section . "/" . $PASSED_ID . ".php")) {
								deleteContentFile($section, $PASSED_ID);
							}
						}

						# Get ID and section with quotes removed
						$page_id = preg_replace("/\"/", "", $sql_insert_array["p_id"]);
						$page_section = preg_replace("/\"/", "", $sql_insert_array["p_section"]);

						# Update any children pages
						$sql2 = "UPDATE " . $PROJECT_DB_TABLES["pages"] . " SET p_parent = '" . $page_id . "' WHERE p_parent = '" . $PASSED_ID . "'";
						executeSQLQuery($sql2);

						# Try to create
						if (createContentFile($page_section, $page_id)) {

							addMessage($saved_ok_message);
						} else {

							addMessage($saved_fail_message, 2);
						}

						# Update Passed ID
						$PASSED_ID = $page_id;

					} else {
						addMessage($saved_ok_message);
					}

				} else {

					addMessage($saved_fail_message, 2);
				}
			}

		# Show errors
		} else {

			foreach ($error_array as $error_id => $error_msg) {
				addMessage("<p>" . $error_msg . "</p>", 2);
			}
		}
	}

	/*
	 *replace the asc2 code with html math code. 
	*/
	function replaceMessyCode($output){
		$output=str_replace(chr(195),"&#915;",$output);
		$output=str_replace(chr(196),"&#916;",$output);
		$output=str_replace(chr(197),"&#917;",$output);
		$output=str_replace(chr(198),"&#918;",$output);
		$output=str_replace(chr(199),"&#919;",$output);
		$output=str_replace(chr(200),"&#920;",$output);
		$output=str_replace(chr(201),"&#921;",$output);
		$output=str_replace(chr(202),"&#922;",$output);
		$output=str_replace(chr(203),"&#923;",$output);
		$output=str_replace(chr(204),"&#924;",$output);
		$output=str_replace(chr(205),"&#925;",$output);
		$output=str_replace(chr(206),"&#926;",$output);
		$output=str_replace(chr(207),"&#927;",$output);
		$output=str_replace(chr(208),"&#928;",$output);
		$output=str_replace(chr(209),"&#929;",$output);
		$output=str_replace(chr(211),"&#931;",$output);
		$output=str_replace(chr(212),"&#932;",$output);
		$output=str_replace(chr(213),"&#933;",$output);
		$output=str_replace(chr(214),"&#934;",$output);
		$output=str_replace(chr(215),"&#935;",$output);
		$output=str_replace(chr(216),"&#936;",$output);
		$output=str_replace(chr(217),"&#937;",$output);
		$output=str_replace(chr(225),"&#945;",$output);
		$output=str_replace(chr(226),"&#946;",$output);
		$output=str_replace(chr(227),"&#947;",$output);
		$output=str_replace(chr(228),"&#948;",$output);
		$output=str_replace(chr(229),"&#949;",$output);
		$output=str_replace(chr(230),"&#950;",$output);
		$output=str_replace(chr(231),"&#951;",$output);
		$output=str_replace(chr(232),"&#952;",$output);
		$output=str_replace(chr(233),"&#953;",$output);
		$output=str_replace(chr(234),"&#954;",$output);
		$output=str_replace(chr(235),"&#955;",$output);
		$output=str_replace(chr(236),"&#956;",$output);
		$output=str_replace(chr(237),"&#957;",$output);
		$output=str_replace(chr(238),"&#958;",$output);
		$output=str_replace(chr(239),"&#959;",$output);
		$output=str_replace(chr(240),"&#960;",$output);
		$output=str_replace(chr(241),"&#961;",$output);
		$output=str_replace(chr(242),"&#962;",$output);
		$output=str_replace(chr(243),"&#963;",$output);
		$output=str_replace(chr(244),"&#964;",$output);
		$output=str_replace(chr(245),"&#965;",$output);
		$output=str_replace(chr(246),"&#966;",$output);
		$output=str_replace(chr(247),"&#967;",$output);
		$output=str_replace(chr(248),"&#968;",$output);
		$output=str_replace(chr(249),"&#969;",$output);
		$output=str_replace(chr(257),"&#977;",$output);
		$output=str_replace(chr(258),"&#978;",$output);
		$output=str_replace(chr(262),"&#982;",$output);
		//$output=str_replace(chr(176),"&#896;",$output);
		//$output=str_replace(chr(176),chr(176),$output);
		return $output;
	}

	/**
	 * formatBrowse() returns the formatted browse html
	 *
	 * @param browse_data is the data to format
	 * @param browse_format is the formatting
	 *
	 * @return the HTML ready to be printed
	*/
	function formatBrowse($browse_data = array(), $browse_format = "") {

		# Bring in some commonly used globals
		global $YES_NO_ARRAY;
		global $PROPERTY_TYPE_ARRAY;

		# Apply string escapes to browse data
		foreach ($browse_data as $key => $data) {
			$browse_data[$key] = preg_replace("/\"/", "\\\"", $browse_data[$key]);
		}

		# If nothing provided
		if ($browse_format == "") {

			return "???";

		} else {


			# Insert the row content
			foreach ($browse_data as $element_id => $element_content) {

				$browse_format = preg_replace("/\[" . $element_id . "\]/", $element_content, $browse_format);
			}

			# Evaluate
			eval("$" . "browse_format = " . $browse_format . ";");
			
			# Return
			return $browse_format;
		}
	}


}

/**
 * The TableProperty class handles a property (column) of a table, including producing
 * formatted HTML for browsing/inputing etc, and parsing output for validity
*/
class TableProperty {

	# ID
	var $id;

	# Data
	var $data = array();

	# Name of Property
	# DB Table Field name
	# DB Table
	# Type (see docs)
	# Input format
	# Browse format
	# Browse order
	# Field Required
	# Called in INSERT statement?
	# Called in UPDATE statement

	/**
	 * TableProperty() instantiates the TableProperty class
	 *
	 * @param property_id is the ID of the property
	 * @param initial_parameters are the initial parameters to add to the data array
	*/
	function TableProperty($property_id = "", $initial_parameters = array()) {

		# Assign ID
		$this -> id = $property_id;

		# Add parameters
		foreach ($initial_parameters as $key => $value) {
			$this -> setData($key, $value);
		}
	}

	/**
	 * setParameter() sets a parameter in the data array
	*/
	function setData($key = "", $value = "") {

		# Check key was supplied
		if ($key != "") {

			$this -> data[$key] = $value;
		}
	}

	/**
	 * getParameter() gets the value of a parameter
	*/
	function getData($key = "") {

		# If it exists
		if (array_key_exists($key, $this -> data)) {

			return $this -> data[$key];

		} else {

			return false;
		}
	}

	/**
	 * getID() gets the ID
	 *
	 * @return the property ID
	*/
	function getID() {

		return $this -> id;
	}

	/**
	 * printProperty() returns a print out of the data of the property
	 *
	 * @return a print out
	*/
	function printProperty() {

		# Output
		$output = "<h3>Property: " . $this -> id . "</h3>\n";
		$output .= "<pre>";
		$output .= print_r($this -> data);
		$output .= "</pre>";

		# Return
		return $output;
	}

	/**
	 * formatBrowse() returns the formatted browse html
	 *
	 * @param browse_data is the data to format
	 * @param browse_key is the key for the data array that contains the browse formatting
	 *
	 * @return the HTML ready to be printed
	*/
	function formatBrowse($browse_data = "", $browse_key = "tp_browseformat") {

		if ($this -> data[$browse_key] == "") {

			return $browse_data;

		} else {

			# Create string to evaluate
			$eval_code = preg_replace("/\[VALUE\]/", $browse_data, $this -> data[$browse_key]);

			# Evaluate
			eval("$" . "eval_code = " . $eval_code . ";");

			# Return
			return $eval_code;
		}
	}
}


?>